#include "MemoryManager.h"



// MemoryManager
//{
  // IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT 
  //
  // This is the only static memory that you may use, no other global variables may be
  // created, if you need to save data make it fit in MM_pool
  //
  // IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT






  // Initialize set up any data needed to manage the memory pool
  void MemoryPool::initializeMemoryManager(void)
  {
    // TODO : IMPLEMENT ME
	memset(&MM_pool[0],0,MM_POOL_SIZE);
	Head first(MM_POOL_SIZE-sizeof(Head));
	memcpy(&MM_pool[0],&first,sizeof(Head));
  }

  // return a pointer inside the memory pool
  // If no chunk can accommodate aSize call onOutOfMemory()
//   void* MemoryPool::allocate(int aSize)
//   {
// 	//First fit method
// 	for(int i=0;i<MM_POOL_SIZE;/*NOTHING*/)
// 	{	
// 		Head* iter = (Head*)&MM_pool[i];
// 		//if we have reached a free chunk and have enough memory to satisfy the request
// 		if(iter->free&&iter->chunkSize>=aSize)
// 		{
// 			//set the header to being used
// 			iter->free=false;
// 			//if the chunk size is bigger than the required size and the size of the new head
// 			if(iter->chunkSize>aSize+static_cast<int>(sizeof(Head)))
// 			{
// 				//create a new head at the end of the chunk and set its chunk size
// 				Head nextHead(iter->chunkSize-aSize-sizeof(Head));
// 				//copy it into position at the end of the chunk
// 				memcpy(&MM_pool[i+aSize+sizeof(Head)],&nextHead,sizeof(Head));
// 				//resize the current headers chunk to match the requested memory
// 				iter->chunkSize=aSize;
// 			}
// 			//return a reference to the start of the chunk
// 			return &MM_pool[i+sizeof(Head)];
// 		}
// 		else
// 		{
// 			//move i along to the next head
// 			i+=iter->chunkSize+sizeof(Head);
// 		}
// 	 }
// 	return NULL;
//   }



  // Free up a chunk previously allocated
  void MemoryPool::deallocate(void* aPointer)
  {
	  Head* start = (Head*)((char*)aPointer-sizeof(Head));
	  start->free=true;
	  Head* next = (Head*)((char*)aPointer+sizeof(Head)+start->chunkSize);
  }

  //---
  //--- support routines
  //--- 

  void MemoryPool::unfragment()
  {
	  int i=0;
	while(i<MM_POOL_SIZE)
	{	
		Head* iter = (Head*)&MM_pool[i];
		Head* next = (Head*)&MM_pool[i+iter->chunkSize+sizeof(Head)];
		if(iter->free&&next->free)
		{
			iter->chunkSize+=next->chunkSize+sizeof(Head);
			memset(next,0,sizeof(Head));
		}
		i+=iter->chunkSize+sizeof(Head);
	}
  }

  // Will scan the memory pool and return the total free space remaining
  int MemoryPool::freeRemaining(void)
  {
	  unfragment();
	  int total=0;
	  for(int i=0;i<MM_POOL_SIZE;/*NOTHING*/)
	  {
		  Head* iter = (Head*)&MM_pool[i];
		  if(iter->free)
		  {
			  total+=iter->chunkSize;
		  }
		  i+=iter->chunkSize+sizeof(Head);
	  }

    return total;
  }

  // Will scan the memory pool and return the largest free space remaining
  int MemoryPool::largestFree(void)
  {
    unfragment();
	int largest=0;
	for(int i=0;i<MM_POOL_SIZE;/*NOTHING*/)
	{
		Head* iter = (Head*)&MM_pool[i];
		if(iter->free&&iter->chunkSize>largest)
		{
			largest = iter->chunkSize;
		}
		i+=iter->chunkSize+sizeof(Head);
	}

    return largest;
  }

  // will scan the memory pool and return the smallest free space remaining
  int MemoryPool::smallestFree(void)
  {
	  unfragment();
	int smallest = MM_POOL_SIZE;
	for(int i=0;i<MM_POOL_SIZE;/*NOTHING*/)
	{
		Head* iter = (Head*)&MM_pool[i];
		if(iter->free&&iter->chunkSize<smallest)
		{
			smallest = iter->chunkSize;
		}
		i+=iter->chunkSize+sizeof(Head);
	}

    return smallest;
  }
 //}